package com.project.biz.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.project.biz.CmsUserBalanceBiz;
import com.project.biz.I18nBiz;
import com.project.common.enums.LockEnum;
import com.project.common.exception.ServiceException;
import com.project.entity.CmsUser;
import com.project.entity.CmsUserBalance;
import com.project.mapper.CmsUserBalanceMapper;
import com.project.mapper.CmsUserMapper;
import com.project.redis.RedisClient2;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;

/**
 * @Description: 用户余额业务层接口实现类
 * @Author: zhuchi
 * @CreateDate: 2020/9/10 16:33
 * @Version: 1.0
 */
@Slf4j
@Service
public class CmsUserBalanceBizImpl extends ServiceImpl<CmsUserBalanceMapper, CmsUserBalance> implements CmsUserBalanceBiz {

    /**
     * 注入自身
     */
    @Autowired
    private CmsUserBalanceBiz userBalanceBiz;

    /**
     * 用户
     */
    @Autowired
    private CmsUserMapper userMapper;

    /**
     * Redis服务
     */
    @Autowired
    private RedisClient2 redisClient2;

    /**
     * 国际化
     */
    @Autowired
    private I18nBiz i18nBiz;

    /**
     * 获取用户余额
     * @param userId
     * @return
     */
    public BigDecimal getUserBalance(Long userId){
        BigDecimal balance = this.baseMapper.getUserBalance(userId);
        if (null != balance){
            return balance;
        }else {
            CmsUserBalance insertUserBalance = this.userBalanceBiz.addUserBalance(userId);
            log.info("获取用户余额时,容错添加用户余额表:{}", insertUserBalance);
            return insertUserBalance.getBalance();
        }
    }

    /**
     * 增加用户余额
     * @param userId
     * @param addMoney
     * @return
     */
    public int updateAddUserBalance(Long userId, BigDecimal addMoney){
        int result = 0;
        //增加用户余额分布式锁
        String updateAddUserBalance_lock = LockEnum.UPDATE_ADD_USER_BALANCE.Value() + userId;
        //超时时间（15秒）
        Long expires = System.currentTimeMillis() + Long.parseLong(LockEnum.LOCK_EXPIRES.Value());
        //用户加锁
        if (this.redisClient2.lock(updateAddUserBalance_lock, String.valueOf(expires))){
            try {
                result = this.baseMapper.updateAddUserBalance(userId, addMoney);
            }catch (Exception e){
                e.printStackTrace();
                log.info("用户[{}]增加用户余额时发生异常,增加金额:{}", userId, addMoney);
                throw new ServiceException(e.getMessage());
            }finally {
                //解锁
                this.redisClient2.unlock(updateAddUserBalance_lock, String.valueOf(expires));
            }
        }else {
            //操作太频繁了，请稍后再试
            throw new ServiceException(this.i18nBiz.getMessage("msg.tooOften"));
        }
        return result;
    }

    /**
     * 减少用户余额
     * @param userId
     * @param subMoney
     * @return
     */
    public int updateSubUserBalance(Long userId, BigDecimal subMoney){
        int result = 0;
        //减少用户余额分布式锁
        String updateSubUserBalance_lock = LockEnum.UPDATE_SUB_USER_BALANCE.Value() + userId;
        //超时时间（15秒）
        Long expires = System.currentTimeMillis() + Long.parseLong(LockEnum.LOCK_EXPIRES.Value());
        //用户加锁
        if (this.redisClient2.lock(updateSubUserBalance_lock, String.valueOf(expires))){
            try {
                result =  this.baseMapper.updateSubUserBalance(userId, subMoney);
            }catch (Exception e){
                e.printStackTrace();
                log.info("减少用户[{}]余额时发生异常,参数信息:{}", userId);
                throw new ServiceException(e.getMessage());
            }finally {
                //解锁
                this.redisClient2.unlock(updateSubUserBalance_lock, String.valueOf(expires));
            }
        }else {
            //操作太频繁了，请稍后再试
            throw new ServiceException(this.i18nBiz.getMessage("msg.tooOften"));
        }
        return result;
    }

    /**
     * 获取用户冻结金额
     * @param userId
     * @return
     */
    public BigDecimal getUserFrozenAmount(Long userId){
        BigDecimal frozenAmount = this.baseMapper.getUserFrozenAmount(userId);
        if (null != frozenAmount){
            return frozenAmount;
        }else {
            CmsUserBalance insertUserBalance = this.userBalanceBiz.addUserBalance(userId);
            log.info("获取用户冻结金额时,容错添加用户余额表:{}", insertUserBalance);
            return insertUserBalance.getFrozenAmount();
        }
    }

    /**
     * 增加用户冻结金额
     * @param userId
     * @param addMoney
     * @return
     */
    public int updateAddUserFrozenAmount(Long userId, BigDecimal addMoney){
        int result = 0;
        //增加用户冻结金额分布式锁
        String updateAddUserFrozenAmount_lock = LockEnum.UPDATE_ADD_USER_FROZEN_AMOUNT.Value() + userId;
        //超时时间（15秒）
        Long expires = System.currentTimeMillis() + Long.parseLong(LockEnum.LOCK_EXPIRES.Value());
        //用户加锁
        if (this.redisClient2.lock(updateAddUserFrozenAmount_lock, String.valueOf(expires))){
            try {
                result =  this.baseMapper.updateAddUserFrozenAmount(userId, addMoney);
            }catch (Exception e){
                e.printStackTrace();
                log.info("增加用户[{}]冻结金额时发生异常,参数信息:{}", userId);
                throw new ServiceException(e.getMessage());
            }finally {
                //解锁
                this.redisClient2.unlock(updateAddUserFrozenAmount_lock, String.valueOf(expires));
            }
        }else {
            //操作太频繁了，请稍后再试
            throw new ServiceException(this.i18nBiz.getMessage("msg.tooOften"));
        }
        return result;
    }

    /**
     * 减少用户冻结金额
     * @param userId
     * @param subMoney
     * @return
     */
    public int updateSubUserFrozenAmount(Long userId, BigDecimal subMoney){
        int result = 0;
        //减少用户冻结金额分布式锁
        String updateSubUserFrozenAmount_lock = LockEnum.UPDATE_SUB_USER_FROZEN_AMOUNT.Value() + userId;
        //超时时间（15秒）
        Long expires = System.currentTimeMillis() + Long.parseLong(LockEnum.LOCK_EXPIRES.Value());
        //用户加锁
        if (this.redisClient2.lock(updateSubUserFrozenAmount_lock, String.valueOf(expires))){
            try {
                result =  this.baseMapper.updateSubUserFrozenAmount(userId, subMoney);
            }catch (Exception e){
                e.printStackTrace();
                log.info("减少用户[{}]冻结金额时发生异常,参数信息:{}", userId);
                throw new ServiceException(e.getMessage());
            }finally {
                //解锁
                this.redisClient2.unlock(updateSubUserFrozenAmount_lock, String.valueOf(expires));
            }
        }else {
            //操作太频繁了，请稍后再试
            throw new ServiceException(this.i18nBiz.getMessage("msg.tooOften"));
        }
       return result;
    }

    /**
     * 初始化用户金额记录
     * @param userId
     * @return
     */
    public CmsUserBalance addUserBalance(Long userId){
        //初始化用户金额记录分布式锁
        String addUserBalance_lock = LockEnum.ADD_USER_BALANCE.Value() + userId;
        //超时时间（15秒）
        Long expires = System.currentTimeMillis() + Long.parseLong(LockEnum.LOCK_EXPIRES.Value());
        //用户加锁
        if (this.redisClient2.lock(addUserBalance_lock, String.valueOf(expires))){
            try {
                CmsUserBalance userBalance = new CmsUserBalance();
                userBalance.setBaseUserId(userId);
                userBalance.setBalance(new BigDecimal("0.00"));
                userBalance.setFrozenAmount(new BigDecimal("0.00"));
                int insertUserBalance = this.baseMapper.insert(userBalance);
                log.info("初始化用户金额表记录执行状态:{}", insertUserBalance);
                return userBalance;
            }catch (Exception e){
                e.printStackTrace();
                log.info("初始化用户[{}]金额记录时发生异常,参数信息:{}", userId);
                throw new ServiceException(e.getMessage());
            }finally {
                //解锁
                this.redisClient2.unlock(addUserBalance_lock, String.valueOf(expires));
            }
        }else {
            //操作太频繁了，请稍后再试
            throw new ServiceException(this.i18nBiz.getMessage("msg.tooOften"));
        }
    }

}
